package com.xtool.livewallpaper.transparent

import android.content.Context
import android.graphics.ImageFormat
import android.hardware.Camera
import android.opengl.GLSurfaceView
import android.os.Handler
import android.os.Looper
import android.service.wallpaper.WallpaperService
import android.view.SurfaceHolder
import com.xtool.livewallpaper.WallPaperAliveService
import com.xtool.livewallpaper.WallpaperBootReceiver
import com.xtool.livewallpaper.base.PrefsHelper
import com.xtool.livewallpaper.video.GLES30WallpaperRenderer
import kotlin.math.abs


/**
 *
 * @author haiyanghou
 * @date 2021/4/14
 */
class TransparentWallpaperService : WallpaperService() {
    companion object {
        var instance: CameraWallpaperEngine? = null
    }

    override fun onCreateEngine(): Engine {
        return CameraWallpaperEngine()
    }

    override fun onDestroy() {
        try {
            instance = null
            PrefsHelper.lastWallpaperType = -1
            WallPaperAliveService.isCameraAlive = false
            super.onDestroy()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    inner class CameraWallpaperEngine : Engine() {
        private var mCamera: Camera? = null
        private var cameraView: GLWallpaperSurfaceView? = null
        private var mRenderer: GLES30WallpaperRenderer? = null
        private val isFront: Boolean get() = PrefsHelper.isFrontCamera
        private var retryCount = 0
        private val handler = Handler(Looper.getMainLooper())

        private inner class GLWallpaperSurfaceView(context: Context?) : GLSurfaceView(context) {
            override fun getHolder(): SurfaceHolder {
                return surfaceHolder
            }

            fun onDestroy() {
                super.onDetachedFromWindow()
            }
        }

        fun setIsFront() {
            createCamera()
        }

        private fun createCameraView() {
            cameraView = GLWallpaperSurfaceView(this@TransparentWallpaperService)
            cameraView?.setEGLContextClientVersion(3)
            mRenderer = GLES30WallpaperRenderer(this@TransparentWallpaperService)
            cameraView?.preserveEGLContextOnPause = true
            cameraView?.setRenderer(mRenderer)
            cameraView?.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
            val width = surfaceHolder.surfaceFrame.width()
            val height = surfaceHolder.surfaceFrame.height()
            mRenderer?.setScreenSize(width, height)
        }

        override fun onCreate(surfaceHolder: SurfaceHolder?) {
            try {
                super.onCreate(surfaceHolder)
                instance = this
                PrefsHelper.lastWallpaperType = WallpaperBootReceiver.TYPE_CAMERA
                WallPaperAliveService.isCameraAlive = true
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        override fun onSurfaceCreated(holder: SurfaceHolder?) {
            try {
                super.onSurfaceCreated(holder)
                createCameraView()
                mRenderer?.setScreenSize(
                    surfaceHolder.surfaceFrame.width(),
                    surfaceHolder.surfaceFrame.height()
                )
                createCamera()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        override fun onSurfaceChanged(
            holder: SurfaceHolder?,
            format: Int,
            width: Int,
            height: Int
        ) {
            try {
                super.onSurfaceChanged(holder, format, width, height)
                mRenderer?.setScreenSize(width, height)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        override fun onVisibilityChanged(visible: Boolean) {
            try {
                super.onVisibilityChanged(visible)
                if (mRenderer != null) {
                    if (visible) {
                        createCamera()
                        cameraView?.onResume()
                    } else {
                        cameraView?.onPause()
                        release()
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        override fun onSurfaceDestroyed(holder: SurfaceHolder?) {
            try {
                release()
                cameraView?.onDestroy()
                super.onSurfaceDestroyed(holder)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        private val retryRunnable = Runnable {
            createCamera()
        }

        private fun createCamera() {
            try {
                handler.removeCallbacks(retryRunnable)
                release()
                val cameraId =
                    if (isFront) Camera.CameraInfo.CAMERA_FACING_FRONT else Camera.CameraInfo.CAMERA_FACING_BACK
                mCamera = Camera.open(cameraId).also { camera ->
                    camera.setDisplayOrientation(90)
                    camera?.setPreviewDisplay(cameraView?.holder)
                }
                updateCameraSize()
                mCamera?.startPreview()
                retryCount = 0
            } catch (e: Exception) {
                e.printStackTrace()
                if (retryCount < 10) {
                    retryCount += 1
                    handler.postDelayed(retryRunnable, 300)
                } else {
                    retryCount = 0
                }
            }
        }

        private fun updateCameraSize() {
            val parameters: Camera.Parameters = mCamera?.parameters ?: return
            val bestSize = getBestSize(parameters) ?: return
            parameters.setPreviewSize(bestSize.width, bestSize.height)
            parameters.setPictureSize(bestSize.width, bestSize.height)
            parameters.previewFormat = ImageFormat.NV21
            val focusModes: List<String> = parameters.supportedFocusModes
            if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
            }
            mCamera?.parameters = parameters
            mRenderer?.setVideoSizeAndRotation(bestSize.width, bestSize.height, 0)
        }

        private fun getBestSize(parameters: Camera.Parameters): Camera.Size? {
            val sizes = parameters.supportedPreviewSizes
            var bestSize: Camera.Size? = null
            val uiRatio =
                1f * surfaceHolder.surfaceFrame.height() / surfaceHolder.surfaceFrame.width()
            var minRatio = uiRatio
            for (previewSize in sizes) {
                val cameraRatio = previewSize.width.toFloat() / previewSize.height
                val offset = abs(cameraRatio - uiRatio)
                if (offset < minRatio) {
                    minRatio = offset
                    bestSize = previewSize
                }
                if (uiRatio == cameraRatio) {
                    bestSize = previewSize
                    break
                }
            }
            return bestSize
        }

        private fun release() {
            try {
                mCamera?.stopPreview()
                mCamera?.release()
                mCamera = null
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}